package cas.ihep.alluxio.impl;

import alluxio.AlluxioURI;
import alluxio.client.block.BlockWorkerInfo;
import alluxio.client.file.FileSystem;
import alluxio.client.file.FileSystemContext;
import alluxio.client.file.FileSystemUtils;
import cas.ihep.alluxio.AlluxioFile;
import cas.ihep.alluxio.AlluxioSystem;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtNewConstructor;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.List;

public class AlluxioBaseSystem implements AlluxioSystem{
    private FileSystem mfs;
    private FileSystemContext mCtx;
    private AlluxioInternal mInt;
    private int isLocal;

    public AlluxioBaseSystem()throws Exception{
        mCtx=FileSystemContext.INSTANCE;
        mfs=FileSystem.Factory.get(mCtx);
        mInt=new AlluxioInternal(mCtx);
        isLocal=0;
    }

    public AlluxioFile open(AlluxioURI path)throws IOException {
        return new AlluxioFileIn(this,path).open();
    }

    public AlluxioFile create(AlluxioURI path)throws IOException{
        return new AlluxioFileOut(this,path).open();
    }

    final AlluxioInternal getInternalHandler(){
        return mInt;
    }

    public FileSystemContext getContext() {
        return mCtx;
    }

    public FileSystem getFileSystem() {
        return mfs;
    }

    @Override
    public void close() throws IOException {
        mCtx.close();
    }

    public boolean hasLocalWorker(){
        if(isLocal==0) {
            try {
                List<BlockWorkerInfo> workers = mInt.getWorkerInfoList();
                for (BlockWorkerInfo info : workers) {
                    if (info.getNetAddress().getHost().equals(localHostName)) {
                        isLocal=1;
                        return true;
                    }
                }
                isLocal=2;
                return false;
            } catch (IOException ignored) {
                isLocal=2;
                return false;
            }
        }else{
            return isLocal==1;
        }
    }

    public void persist(AlluxioURI path)throws IOException{
        FileSystemUtils.persistFile(mfs,path);
    }

    private static final Class<AlluxioURI> alluxioURIClass;
    private static final Field mUriField;

    static {
        try{
            ClassPool pool=ClassPool.getDefault();
            CtClass ctAlluxioURIClass=pool.get("alluxio.AlluxioURI");
            ctAlluxioURIClass.addConstructor(CtNewConstructor.defaultConstructor(ctAlluxioURIClass));
            //noinspection unchecked
            alluxioURIClass= (Class<AlluxioURI>) ctAlluxioURIClass.toClass();
            //noinspection JavaReflectionMemberAccess
            mUriField=alluxioURIClass.getField("mUri");
            mUriField.setAccessible(true);
        }catch (RuntimeException e){
            throw e;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public static AlluxioURI newURI(java.net.URI baseUri){
        MyStandardUri uri=new MyStandardUri(baseUri);
        try {
            AlluxioURI ret=alluxioURIClass.newInstance();
            mUriField.set(ret,uri);
            return ret;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    static URI baseURI(AlluxioURI apUri){
        try {
            alluxio.URI aUri = (alluxio.URI) mUriField.get(apUri);
            return aUri.getBaseURI();
        }catch (RuntimeException e){
            throw e;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}
